/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-09-17     tyustli   first version
 */

#include <rtconfig.h> 
#ifdef LCD_USING_TFT_ST77916

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "drv_ospi.h"

#define INST_CMD 0x02
#define DATA_CMD 0x32

#define LCD_RST_PIN GET_PIN(E, 15)  // 复位引脚
#define LCD_CS_PIN GET_PIN(B,11)  // CS引脚

 struct rt_qspi_device * lcd_dev;
 static int rt_qspi_lcd_init(void)
 {
    rt_pin_mode(LCD_RST_PIN, PIN_MODE_OUTPUT);

    // 复位序列
    rt_pin_write(LCD_RST_PIN, 0);  // 拉低复位
    rt_thread_mdelay(10);         // 保持100ms
    rt_pin_write(LCD_RST_PIN, 1);  // 释放复位
    rt_thread_mdelay(10);         // 等待复位完成
 
    rt_hw_ospi_device_attach("ospi1", "ospi10", LCD_CS_PIN, 4, RT_NULL, RT_NULL);
     lcd_dev = (struct rt_qspi_device *)rt_device_find("ospi10");
     struct rt_qspi_configuration cfg={
         .parent={
             .mode=RT_SPI_MODE_0|RT_SPI_MSB,
             .max_hz=10*1000*1000,
             .data_width=8,
            },
         .qspi_dl_width=4,
     };
     rt_qspi_configure(lcd_dev, &cfg);   
 
     return RT_EOK;
 }
 
//  INIT_ENV_EXPORT(rt_qspi_lcd_init);
 

 static int rt_qspi_send_msg_test2(void)
 {
     // struct rt_qspi_device *lcd_dev = (struct rt_qspi_device *)rt_device_find("qspi10");
     struct rt_qspi_message msg={
        .parent={
            .send_buf=(uint8_t []){0x11, 0x22, 0x33, 0x44, 0x55},
            .recv_buf=RT_NULL,
            .length=5,
            .cs_take=1,
            .cs_release=1,
            .next=RT_NULL,
        },
        .instruction={
            .content=INST_CMD,
            .qspi_lines=1,
        },
       .address={
           .content=0x003A00,
           .size=24,
           .qspi_lines=1,
        },
       .alternate_bytes={
           .content=0x00,
           .size=0,
           .qspi_lines=0,
        },
       .dummy_cycles=0,
       .qspi_data_lines=1,
     };
     rt_qspi_transfer_message(lcd_dev, &msg);
 
     return RT_EOK;
 }
 
 MSH_CMD_EXPORT(rt_qspi_send_msg_test2, rt_qspi_send_msg_test2!)
 
 
 void write_command(uint8_t cmd)
 {
     /*qspi单线发指令，用于qspi lcd初始化*/
     rt_qspi_send(lcd_dev, (uint8_t []){INST_CMD,0x00,cmd,0x00}, 4);
 }
 
 void write_command_data(uint8_t cmd, uint8_t *pdata, uint32_t length)
 {
     /*qspi单线发指令和数据，用于qspi lcd初始化*/
     struct rt_qspi_message msg = {
         .parent = {
             .send_buf = pdata,
             .recv_buf = RT_NULL,
             .length = length,
             .cs_take = 1,
             .cs_release = 1,
             .next = RT_NULL
         },
         .instruction = {
             .content = INST_CMD,
             .qspi_lines = 1
         },
         .address = {
             .content = cmd<<8,
             .size = 24,
             .qspi_lines = 1
         },
         .alternate_bytes = {
             .content = 0x00,
             .size = 0,
             .qspi_lines = 0
         },
         .dummy_cycles = 0,
         .qspi_data_lines = 1
     };
     rt_qspi_transfer_message(lcd_dev, &msg);
 }
 
 void write_command_pixels(uint8_t cmd, uint8_t *pdata, uint32_t length)
 {
     /*qspi单线发指令，4线发数据，用于qspi lcd初始化*/
     struct rt_qspi_message msg = {
         .parent = {
             .send_buf = pdata,
             .recv_buf = RT_NULL,
             .length = length,
             .cs_take = 1,
             .cs_release = 1,
             .next = RT_NULL
         },
         .instruction = {
             .content = DATA_CMD,
             .qspi_lines = 1
         },
         .address = {
             .content = cmd<<8,
             .size = 24,
             .qspi_lines = 1
         },
         .alternate_bytes = {
             .content = 0x00,
             .size = 0,
             .qspi_lines = 0
         },
         .dummy_cycles = 0,
         .qspi_data_lines = 4
     };
     rt_qspi_transfer_message(lcd_dev, &msg);
 }
 
 
 #define MAX_CMD_LEN 32
 static uint8_t lcd_init_cmds[][MAX_CMD_LEN] = {
    //  {0x01, 0},      /*soft reset*/
    //  {0x0, 1, 120},  /*这条伪指令表示延时120ms*/

     {0x3A, 1, 0x55},
     {0xF0, 1, 0x08},
     {0xF2, 1, 0x08},
     {0x9B, 1, 0x51},
     {0x86, 1, 0x53},
     {0xF2, 1, 0x80},
     {0xF0, 1, 0x00},
     {0xF0, 1, 0x01},
     {0xF1, 1, 0x01},
     {0xB0, 1, 0x54},
     {0xB1, 1, 0x3F},
     {0xB2, 1, 0x2A},
     {0xB4, 1, 0x46},
     {0xB5, 1, 0x34},
     {0xB6, 1, 0xD5},
     {0xB7, 1, 0x30},
     {0xBA, 1, 0x00},
     {0xBB, 1, 0x08},
     {0xBC, 1, 0x08},
     {0xBD, 1, 0x00},
     {0xC0, 1, 0x80},
     {0xC1, 1, 0x10},
     {0xC2, 1, 0x37},
     {0xC3, 1, 0x80},
     {0xC4, 1, 0x10},
     {0xC5, 1, 0x37},
     {0xC6, 1, 0xA9},
     {0xC7, 1, 0x41},
     {0xC8, 1, 0x51},
     {0xC9, 1, 0xA9},
     {0xCA, 1, 0x41},
     {0xCB, 1, 0x51},
     {0xD0, 1, 0x91},
     {0xD1, 1, 0x68},
     {0xD2, 1, 0x69},
     {0xF5, 2, 0x00, 0xA5},
     {0xDD, 1, 0x3F},
     {0xDE, 1, 0x3F},
     {0xF1, 1, 0x10},
     {0xF0, 1, 0x00},
     {0xF0, 1, 0x02},
     {0xE0, 14, 0xF0, 0x06, 0x0B, 0x09, 0x09, 0x16, 0x32, 0x44, 0x4A, 0x37, 0x13,
      0x13, 0x2E, 0x34},
     {0xE1, 14, 0xF0, 0x06, 0x0B, 0x09, 0x08, 0x05, 0x32, 0x33, 0x49, 0x17, 0x13,
      0x13, 0x2E, 0x34},
     {0xF0, 1, 0x10},
     {0xF3, 1, 0x10},
     {0xE0, 1, 0x0A},
     {0xE1, 1, 0x00},
     {0xE2, 1, 0x00},
     {0xE3, 1, 0x00},
     {0xE4, 1, 0xE0},
     {0xE5, 1, 0x06},
     {0xE6, 1, 0x21},
     {0xE7, 1, 0x00},
     {0xE8, 1, 0x05},
     {0xE9, 1, 0x82},
     {0xEA, 1, 0xDF},
     {0xEB, 1, 0x89},
     {0xEC, 1, 0x20},
     {0xED, 1, 0x14},
     {0xEE, 1, 0xFF},
     {0xEF, 1, 0x00},
     {0xF8, 1, 0xFF},
     {0xF9, 1, 0x00},
     {0xFA, 1, 0x00},
     {0xFB, 1, 0x30},
     {0xFC, 1, 0x00},
     {0xFD, 1, 0x00},
     {0xFE, 1, 0x00},
     {0xFF, 1, 0x00},
     {0x60, 1, 0x42},
     {0x61, 1, 0xE0},
     {0x62, 1, 0x40},
     {0x63, 1, 0x40},
     {0x64, 1, 0x02},
     {0x65, 1, 0x00},
     {0x66, 1, 0x40},
     {0x67, 1, 0x03},
     {0x68, 1, 0x00},
     {0x69, 1, 0x00},
     {0x6A, 1, 0x00},
     {0x6B, 1, 0x00},
     {0x70, 1, 0x42},
     {0x71, 1, 0xE0},
     {0x72, 1, 0x40},
     {0x73, 1, 0x40},
     {0x74, 1, 0x02},
     {0x75, 1, 0x00},
     {0x76, 1, 0x40},
     {0x77, 1, 0x03},
     {0x78, 1, 0x00},
     {0x79, 1, 0x00},
     {0x7A, 1, 0x00},
     {0x7B, 1, 0x00},
     {0x80, 1, 0x48},
     {0x81, 1, 0x00},
     {0x82, 1, 0x05},
     {0x83, 1, 0x02},
     {0x84, 1, 0xDD},
     {0x85, 1, 0x00},
     {0x86, 1, 0x00},
     {0x87, 1, 0x00},
     {0x88, 1, 0x48},
     {0x89, 1, 0x00},
     {0x8A, 1, 0x07},
     {0x8B, 1, 0x02},
     {0x8C, 1, 0xDF},
     {0x8D, 1, 0x00},
     {0x8E, 1, 0x00},
     {0x8F, 1, 0x00},
     {0x90, 1, 0x48},
     {0x91, 1, 0x00},
     {0x92, 1, 0x09},
     {0x93, 1, 0x02},
     {0x94, 1, 0xE1},
     {0x95, 1, 0x00},
     {0x96, 1, 0x00},
     {0x97, 1, 0x00},
     {0x98, 1, 0x48},
     {0x99, 1, 0x00},
     {0x9A, 1, 0x0B},
     {0x9B, 1, 0x02},
     {0x9C, 1, 0xE3},
     {0x9D, 1, 0x00},
     {0x9E, 1, 0x00},
     {0x9F, 1, 0x00},
     {0xA0, 1, 0x48},
     {0xA1, 1, 0x00},
     {0xA2, 1, 0x04},
     {0xA3, 1, 0x02},
     {0xA4, 1, 0xDC},
     {0xA5, 1, 0x00},
     {0xA6, 1, 0x00},
     {0xA7, 1, 0x00},
     {0xA8, 1, 0x48},
     {0xA9, 1, 0x00},
     {0xAA, 1, 0x06},
     {0xAB, 1, 0x02},
     {0xAC, 1, 0xDE},
     {0xAD, 1, 0x00},
     {0xAE, 1, 0x00},
     {0xAF, 1, 0x00},
     {0xB0, 1, 0x48},
     {0xB1, 1, 0x00},
     {0xB2, 1, 0x08},
     {0xB3, 1, 0x02},
     {0xB4, 1, 0xE0},
     {0xB5, 1, 0x00},
     {0xB6, 1, 0x00},
     {0xB7, 1, 0x00},
     {0xB8, 1, 0x48},
     {0xB9, 1, 0x00},
     {0xBA, 1, 0x0A},
     {0xBB, 1, 0x02},
     {0xBC, 1, 0xE2},
     {0xBD, 1, 0x00},
     {0xBE, 1, 0x00},
     {0xBF, 1, 0x00},
     {0xC0, 1, 0x12},
     {0xC1, 1, 0xAA},
     {0xC2, 1, 0x65},
     {0xC3, 1, 0x74},
     {0xC4, 1, 0x47},
     {0xC5, 1, 0x56},
     {0xC6, 1, 0x00},
     {0xC7, 1, 0x88},
     {0xC8, 1, 0x99},
     {0xC9, 1, 0x33},
     {0xD0, 1, 0x21},
     {0xD1, 1, 0xAA},
     {0xD2, 1, 0x65},
     {0xD3, 1, 0x74},
     {0xD4, 1, 0x47},
     {0xD5, 1, 0x56},
     {0xD6, 1, 0x00},
     {0xD7, 1, 0x88},
     {0xD8, 1, 0x99},
     {0xD9, 1, 0x33},
     {0xF3, 1, 0x01},
     {0xF0, 1, 0x00},
     {0xF0, 1, 0x01},
     {0xF1, 1, 0x01},
     {0xA0, 1, 0x0B},
     {0xA3, 1, 0x2A},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x2B},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x2C},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x2D},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x2E},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x2F},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x30},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x31},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x32},
     {0xA5, 1, 0xC3},
     {0xA3, 1, 0x33},
     {0xA5, 1, 0xC3},
     {0xA0, 1, 0x09},
     {0xF1, 1, 0x10},
     {0xF0, 1, 0x00},
     {0x2A, 4, 0x00, 0x00, 0x01, 0x67},
     {0x2B, 4, 0x00, 0x00, 0x01, 0x68},
     {0x4D, 1, 0x00},
     {0x4E, 1, 0x00},
     {0x4F, 1, 0x00},
     {0x4C, 1, 0x01},
     {0x4C, 1, 0x00},
     {0x2A, 4, 0x00, 0x00, 0x01, 0x67},
     {0x2B, 4, 0x00, 0x00, 0x01, 0x67},
     {0x21, 0},
 
     {0x11, 0},
     {0x0, 1, 120},  /*这条伪指令表示延时120ms*/
     {0x29, 0}, 
     
     // {0x36, 1, 0x20},   //0x20=旋转90度，0x00=不旋转
 };
 
 static int lcd_init()
 {
    rt_qspi_lcd_init();

     for (int i = 0; i < sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]); i++) {
         if (lcd_init_cmds[i][0] == 0x0) {
             rt_thread_mdelay(lcd_init_cmds[i][2]);
         }
         else if (lcd_init_cmds[i][1] == 0) {
             write_command(lcd_init_cmds[i][0]);
         }
         else {
             write_command_data(lcd_init_cmds[i][0], &lcd_init_cmds[i][2], lcd_init_cmds[i][1]);
         }
     }
 }
 
 INIT_ENV_EXPORT(lcd_init);
 
 void lcd_fill_pixels(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint8_t *pcolor)
 {
     uint8_t xwin_list[]={(x0>>8)&0xff, x0&0xff, (x1>>8)&0xff, x1&0xff};
     uint8_t ywin_list[]={(y0>>8)&0xff, y0&0xff, (y1>>8)&0xff, y1&0xff};
     write_command_data(0x2a, xwin_list, 4);
     write_command_data(0x2b, ywin_list, 4);
 
     uint32_t length=2*(x1-x0+1)*(y1-y0+1);
     write_command_pixels(0x2c, (uint8_t *)pcolor, length);
 }
 
 void lcd_fill_block(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t color)
 {
     uint8_t xwin_list[]={(x0>>8)&0xff, x0&0xff, (x1>>8)&0xff, x1&0xff};
     uint8_t ywin_list[]={(y0>>8)&0xff, y0&0xff, (y1>>8)&0xff, y1&0xff};
     write_command_data(0x2a, xwin_list, 4);
     write_command_data(0x2b, ywin_list, 4);
 
     uint32_t length=2*(x1-x0+1)*(y1-y0+1);
     uint8_t *pcolor=rt_malloc(length);
     for(int i=0;i<length;i+=2){
         pcolor[i]=color>>8;
         pcolor[i+1]=color&0xff;
     }
     write_command_pixels(0x2c, (uint8_t *)pcolor, length);
     rt_free(pcolor);
 }
 
 void lcd_clear(uint32_t color)
 {
     lcd_fill_block(0, 0, LCD_W - 1, LCD_H - 1, color);
 }
 
 static void lcd_clear_test()
 {
     lcd_clear(0xf800); rt_thread_mdelay(500);
     lcd_clear(0x07e0); rt_thread_mdelay(500);
     lcd_clear(0x001f); rt_thread_mdelay(500);   
 }
 
 MSH_CMD_EXPORT(lcd_clear_test, lcd_clear_test!)
 
 #endif